package com.hss.common.utils;


import java.net.InetAddress;
import java.security.MessageDigest;

/**
 * @author JimmyLee
 *
 * @createDate 2009-2-3
 *
 */

public class UUIDHelper {
    private static UUIDHelper instance = new UUIDHelper();

    private UUIDHelper() {
    }

    private static final int IP;

    static {
        int ipadd;
        try {
            ipadd = bytesAsInt(InetAddress.getLocalHost().getAddress());
        } catch (Exception e) {
            ipadd = 0;
        }
        IP = ipadd;
    }
    
    private static short counter = (short) 0;
    private static final int JVM = (int) (System.currentTimeMillis() >>> 8);

    /**
     * Unique across JVMs on this machine (unless they load this class
     * in the same quater second - very unlikely)
     */
    private int getJVM() {
        return JVM;
    }

    /**
     * Unique in a millisecond for this JVM instance (unless there
     * are > Short.MAX_VALUE instances created in a millisecond)
     */
    private short getCount() {
        synchronized (this) {
            if (counter < 0) counter = 0;
            return counter++;
        }
    }

    private int getIP() {
        return IP;
    }

    private short getHiTime() {
        return (short) (System.currentTimeMillis() >>> 32);
    }

    private int getLoTime() {
        return (int) System.currentTimeMillis();
    }
    
    private String formatHex(int intval) {
        String formatted = Integer.toHexString(intval);
        StringBuffer buf = new StringBuffer("00000000");
        buf.replace(8 - formatted.length(), 8, formatted);
        return buf.toString();
    }

    private String formatHex(short shortval) {
        String formatted = Integer.toHexString(shortval);
        StringBuffer buf = new StringBuffer("0000");
        buf.replace(4 - formatted.length(), 4, formatted);
        return buf.toString();
    }

    public String generateHex() {
        return new StringBuffer(32)
                .append(formatHex(getIP()))
                .append(formatHex(getJVM()))
                .append(formatHex(getHiTime()))
                .append(formatHex(getLoTime()))
                .append(formatHex(getCount()))
                .toString();
    }

    public static String hash() {
        return encodeMD5(instance.generateHex());
    }

    public static String hash36() {
        String str = encodeMD5(instance.generateHex());
        str = new StringBuffer(str)
        	.insert(20, '-')
        	.insert(16, '-')
        	.insert(12, '-')
        	.insert(8, '-')
        	.toString();
        return str;
    }
    
	/**
	 * 将一个 byte[4] 按照字节顺序，转换成 int
	 */
    private static int bytesAsInt(byte[] bytes) {
		int val = 0;
		for (int i = 0; i < bytes.length; i++) {
			val = (val << 8) + (bytes[i] & 0xff);
		}
		return val;
	}
    /**
     * 进行 MD5 编码
     */
	private static String encodeMD5(String text) {
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("MD5");
            md.update(text.getBytes("ISO8859-1"));
            byte[] digest = md.digest();
            return encodeHex(digest);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    private final static char[] HEX_CHAR_ARRAY = {
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        'a', 'b', 'c', 'd', 'e', 'f'
    };
    
    /**
     * encodeHex() 用来把一个byte类型的数转换成十六进制的ASCII表示，
     * 因为java中的byte的toString无法实现这一点，我们又没有C语言中的
     * sprintf(outbuf,"%02X",ib)
     */
    private static String encodeHex(byte b) {
        char[] ob = new char[2];
        ob[0] = HEX_CHAR_ARRAY[(b >>> 4) & 0X0F];
        ob[1] = HEX_CHAR_ARRAY[b & 0X0F];
        return new String(ob); // new String(ob, "GBK")
    }

    /**
     * encodeHex() 用来把一个byte类型的数转换成十六进制的ASCII表示，
     * 因为java中的byte的toString无法实现这一点，我们又没有C语言中的
     * sprintf(outbuf,"%02X",ib)
     */
    private static String encodeHex(byte[] bytes) {
        StringBuffer sb = new StringBuffer(bytes.length);
        for (int i = 0; i < bytes.length; i++) {
            sb.append(encodeHex(bytes[i]));
        }
        return sb.toString();
    }
    

}